﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Nox.Amuse.MVVM;
using Nox.Amuse.Model;
using Nox.Amuse.Helpers;
using System.Windows;
using System.Windows.Input;
using System.ComponentModel;
using System.Net;
using System.Windows.Media;
using Nox.Amuse.View;

namespace Nox.Amuse.ViewModel
{
    public class UpdateViewModel : ObservableObject
    {
        // Use the instance model so no one else has to hold on to this
        private static UpdateViewModel myInstance;

        public static UpdateViewModel CurrentUpdateViewModel
        {
            get { return myInstance; }
        }

        public static void Initialize(bool isTestMode)
        {
            if (myInstance == null)
                myInstance = new UpdateViewModel(isTestMode);
        }

        // Held on to by App, masks and protects underlying app data in Update and Update Settings.
        // Can plugin to other View's and provide data for their interfaces

        private UpdateSettings myUpdateSettingsModel;

        public bool IsStatusDialogOpen { get; set; }

        public bool IsFirstRunPostUpdate { get; private set; }

        private UpdateViewModel(bool isTestMode)
        {
            App.Messenger.Register(Messages.UpdateCheckStarted, () => UpdateCheckStartedHandler());
            App.Messenger.Register(Messages.UpdateCheckComplete, () => UpdateCheckCompletedHandler());
            App.Messenger.Register(Messages.UpdateAvalible, () => UpdateAvalibleHandler());
            App.Messenger.Register<DownloadProgressChangedEventArgs>(Messages.UpdateDownloadProgress, (e) => UpdateProgressHandler(e));
            App.Messenger.Register<Exception>(Messages.UpdateDownloadFailed, (fault) => UpdateDownloadFailedHandler(fault));
            App.Messenger.Register(Messages.UpdateDownloadComplete, () => UpdateDownloadCompleteHandler());
            App.Messenger.Register(Messages.UpdateDownloadCancelled, () => UpdateDownloadCancelledHandler());
            myUpdateSettingsModel = UpdateSettings.Load();
            IsFirstRunPostUpdate = myUpdateSettingsModel.PerformUpdateStatusCheck();
            myUpdateSettingsModel.BeginAutoUpdateTimer();
            myUpdateSettingsModel.IsTestMode = isTestMode;
        }

        /// <summary>
        /// Displays the Status User Interface if its not already visible
        /// </summary>
        private void PopUI()
        {
            if (!IsStatusDialogOpen)
            {
                var updateStatusDialog = new UpdateStatusDialog { DataContext = UpdateViewModel.CurrentUpdateViewModel, Owner = Application.Current.MainWindow };
                updateStatusDialog.Show();
            }
        }

        private void UpdateDownloadCancelledHandler()
        {
            UpdateUIStatus(UpdateStatus.Pending);
            ProgressValue = 0;
            var t = App.Current.MainWindow.TaskbarItemInfo;
            t.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
            t.Overlay = null;
        }

        private void UpdateDownloadFailedHandler(Exception fault)
        {
            DownloadText = String.Format("Error Details: {0}", fault.Message);
            var t = App.Current.MainWindow.TaskbarItemInfo;
            t.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Error;
            t.Overlay = ImageHelper.GetImageSourceFromResource("update_circle_red_16.png");
            UpdateUIStatus(UpdateStatus.Error);
            PopUI();
        }

        private void UpdateDownloadCompleteHandler()
        {
            var t = App.Current.MainWindow.TaskbarItemInfo;
            t.Overlay = ImageHelper.GetImageSourceFromResource("update_circle_green_16.png");
            ProgressValue = 100;
            UpdateUIStatus(UpdateStatus.Downloaded);
            PopUI();
        }

        private void UpdateProgressHandler(DownloadProgressChangedEventArgs e)
        {
            var t = App.Current.MainWindow.TaskbarItemInfo;
            t.ProgressValue = (double)e.ProgressPercentage / 100;
            DownloadText = String.Format("{0}% Complete - {1}KB of {2}KB transferred", e.ProgressPercentage,
                e.BytesReceived / 1000, e.TotalBytesToReceive / 1000);
            ProgressValue = e.ProgressPercentage;
        }

        private void UpdateAvalibleHandler()
        {
            UpdateUIStatus(UpdateStatus.Pending);
            PopUI();
        }

        private void UpdateCheckStartedHandler()
        {
            var t = App.Current.MainWindow.TaskbarItemInfo;
            t.Overlay = ImageHelper.GetImageSourceFromResource("update_circle_16.png");
        }

        private void UpdateCheckCompletedHandler()
        {
            var t = App.Current.MainWindow.TaskbarItemInfo;
            t.Overlay = null;
            if (!myUpdateSettingsModel.IsUpdateNewer())
            {
                UpdateUIStatus(UpdateStatus.Idle);
                if (IsStatusDialogOpen)
                    MessageBox.Show("No updates are avalible", "Placeholder Alert", MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }

        public string StatusMainInstruction
        {
            get
            {
                switch (myStatus)
                {
                    case UpdateStatus.Idle:
                        return "Check for updates";
                    case UpdateStatus.Checking:
                        return "Checking for updates...";
                    case UpdateStatus.Pending:
                        return "Amuse Update found";
                    case UpdateStatus.Downloading:
                        return "Downloading updates...";
                    case UpdateStatus.Downloaded:
                        return "Ready to update Amuse";
                    case UpdateStatus.Error:
                        return "An error occured while trying to download the update";
                    default:
                        return "Wibble";
                }
            }
        }

        public string StatusSecondaryText
        {
            get
            {
                switch (myStatus)
                {
                    case UpdateStatus.Idle:
                        return "Amuse will automatically check for updates periodically.";
                    case UpdateStatus.Checking:
                        return "Please wait a moment.";
                    case UpdateStatus.Pending:
                        return "An update to Amuse is ready to download.";
                    case UpdateStatus.Downloading:
                        return "Please wait while the update is downloaded.";
                    case UpdateStatus.Downloaded:
                        return "An update for Amuse is ready to install.";
                    case UpdateStatus.Error:
                        return "Please check your internet connection and then try again.";
                    default:
                        return "Wobble";
                }
            }
        }

        public bool ProgressState
        {
            get
            {
                switch (myStatus)
                {
                    case UpdateStatus.Checking:
                        return true;
                    default:
                        return false;
                }
            }
        }

        public Brush ProgressColor
        {
            get
            {
                if (myStatus == UpdateStatus.Error)
                    return new SolidColorBrush(Colors.Red);
                else
                    return App.Current.FindResource("ProgressGreenBrush") as SolidColorBrush;
            }
        }

        public Visibility ProgressVisibility
        {
            get
            {
                switch (myStatus)
                {
                    case UpdateStatus.Idle:
                        return Visibility.Collapsed;
                    default:
                        return Visibility.Visible;
                }
            }
        }

        double myProgressValue = 0;
        public double ProgressValue
        {
            get { return myProgressValue; }
            private set
            {
                myProgressValue = value;
                this.RaisePropertyChanged("ProgressValue");
            }
        }

        string myDownloadText = "Preparing to download...";
        public string DownloadText
        {
            get { return myDownloadText; }
            private set
            {
                myDownloadText = value;
                this.RaisePropertyChanged("DownloadText");
            }
        }
        public Visibility DownloadTextVisibility
        {
            get
            {
                switch (myStatus)
                {
                    case UpdateStatus.Downloading:
                        return Visibility.Visible;
                    case UpdateStatus.Error:
                        return Visibility.Visible;
                    default:
                        return Visibility.Collapsed;
                }
            }
        }

        public Visibility ExdownloadVisibility
        {
            get
            {
                switch (myStatus)
                {
                    case UpdateStatus.Pending:
                        return Visibility.Visible;
                    case UpdateStatus.Error:
                        return Visibility.Visible;
                    case UpdateStatus.Downloaded:
                        return Visibility.Visible;
                    default:
                        return Visibility.Collapsed;
                }
            }
        }

        public string StatusCommitText
        {
            get
            {
                switch (myStatus)
                {
                    case UpdateStatus.Idle:
                        return "Check for _updates";
                    case UpdateStatus.Checking:
                        return "Check for _updates";
                    case UpdateStatus.Pending:
                        return "_Download Now";
                    case UpdateStatus.Downloading:
                        return "_Stop Download";
                    case UpdateStatus.Downloaded:
                        return "_Install Update";
                    case UpdateStatus.Error:
                        return "_Try Again";
                    default:
                        return "Wobble";
                }
            }
        }

        public ICommand StatusCommitCommand
        {
            get
            {
                return myStatusCommitCommand ?? (myStatusCommitCommand = new RelayCommand(
                    () =>
                    {
                        var t = App.Current.MainWindow.TaskbarItemInfo;
                        // Action
                        switch (myStatus)
                        {
                            case UpdateStatus.Idle:
                                UpdateUIStatus(UpdateStatus.Checking);
                                myUpdateSettingsModel.ForceCheckForUpdates();
                                break;
                            case UpdateStatus.Pending:
                                t.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal;
                                t.Overlay = ImageHelper.GetImageSourceFromResource("update_circle_16.png");
                                UpdateUIStatus(UpdateStatus.Downloading);
                                myUpdateSettingsModel.BeginUpdateDownload();
                                break;
                            case UpdateStatus.Error:
                                t.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal;
                                t.Overlay = ImageHelper.GetImageSourceFromResource("update_circle_16.png");
                                UpdateUIStatus(UpdateStatus.Downloading);
                                myUpdateSettingsModel.BeginUpdateDownload();
                                break;
                            case UpdateStatus.Downloading:
                                UpdateUIStatus(UpdateStatus.Pending);
                                myUpdateSettingsModel.StopUpdateDownload();
                                break;
                            case UpdateStatus.Downloaded:
                                if (System.Windows.MessageBox.Show("Amuse must exit to update. Do you wish to exit now?",
                                    "Placeholder Alert",
                                    System.Windows.MessageBoxButton.YesNo,
                                    System.Windows.MessageBoxImage.None,
                                    System.Windows.MessageBoxResult.No) == System.Windows.MessageBoxResult.Yes)
                                {
                                    App.IsReadyToExit = true;
                                    if (myUpdateSettingsModel.RunUpdate())
                                    {
                                        // If the update started okay...
                                        App.Current.Shutdown();
                                    }
                                    // Don't do anything else, user may of cancelled at the UAC dialog
                                }
                                break;
                            default:
                                break;
                        }
                    },
                    () =>
                    {
                        // Test
                        switch (myStatus)
                        {
                            case UpdateStatus.Checking:
                                return false;
                            default:
                                return true;
                        }
                    }
                    ));
            }
        }
        private RelayCommand myStatusCommitCommand;

        public ICommand ExDownloadCommand
        {
            get
            {
                return myExDownloadCommand ?? (myExDownloadCommand = new RelayCommand(
                    () =>
                    {
                        if (!myUpdateSettingsModel.StartExternalUpdateDownload())
                        {
                            System.Windows.MessageBox.Show("Amuse was unable to start your web browser. Please download the update manually from http://amuse.codeplex.com",
                                    "Placeholder Alert",
                                    System.Windows.MessageBoxButton.OK,
                                    System.Windows.MessageBoxImage.Error);
                        }
                    }));
            }
        }
        private RelayCommand myExDownloadCommand;

        public string MostRecentCheckTimeDate
        {
            get
            {
                if (myUpdateSettingsModel.LastSuccessfulCheckTime != null)
                {
                    var t = myUpdateSettingsModel.LastSuccessfulCheckTime;
                    return String.Format("{0} - {1}", t.ToShortTimeString(), t.ToLongDateString());
                }
                else
                    return "Never";
            }
        }

        private UpdateStatus myStatus = UpdateStatus.Idle;

        private void UpdateUIStatus(UpdateStatus newStatus)
        {
            myStatus = newStatus;
            this.RaisePropertyChanged("StatusMainInstruction");
            this.RaisePropertyChanged("StatusSecondaryText");
            this.RaisePropertyChanged("ProgressState");
            this.RaisePropertyChanged("ProgressVisibility");
            this.RaisePropertyChanged("ProgressValue");
            this.RaisePropertyChanged("ProgressColor");
            this.RaisePropertyChanged("DownloadTextVisibility");
            this.RaisePropertyChanged("ExdownloadVisibility");
            this.RaisePropertyChanged("StatusCommitText");
            CommandManager.InvalidateRequerySuggested();
        }

        enum UpdateStatus
        {
            Idle,
            Checking,
            Pending,
            Downloading,
            Downloaded,
            Error
        }

    }
}
